

#include "gd32w51x.h"
#include "BSP_Uart_2.h"

#include <stdint.h>
#include "i7816_define.h"
#include "i7816_utils.h"
#include "i7816_hal.h"
#include "i7816_hal_usart_define.h"
#include "i7816_log.h"

/*======================================数据收发===============================================*/

static uint32_t i7816_hal_usart_get_freq(uint32_t periph)
{
	if(periph == USART2)
	{
		return rcu_clock_freq_get(CK_APB2);
	}
	return rcu_clock_freq_get(CK_APB1);
}

static void i7816_hal_usart_set_freq(uint32_t periph, uint32_t freq){
	uint32_t usart_freq = i7816_hal_usart_get_freq(periph);
    uint32_t div = usart_freq / freq;
	usart_prescaler_config(periph, div / 2);
}

static void i7816_hal_usart_dev_init(uint32_t periph, uint32_t freq)
{
    /* disable the peripheral */
    usart_disable(periph);

	i7816_hal_usart_set_freq(periph, freq);

    /* baud rate configure */
    usart_baudrate_set(periph, 10752);
    usart_parity_config(periph, USART_PM_EVEN);
    usart_word_length_set(periph, USART_WL_9BIT);
    usart_stop_bit_set(periph, USART_STB_1_5BIT);
    usart_transmit_config(periph, USART_TRANSMIT_ENABLE);
    usart_receive_config(periph, USART_RECEIVE_ENABLE);
    usart_sample_bit_config(periph, USART_OSB_3BIT);
    usart_guard_time_config(periph, 1);
    usart_smartcard_mode_nack_disable(periph);
    usart_receiver_timeout_disable(periph);
    usart_block_length_config(periph, 0);
    usart_smartcard_autoretry_config(periph, 0);
    usart_synchronous_clock_config(periph, USART_CLEN_EN, USART_CPH_1CK, USART_CPL_LOW);
    usart_clock_enable(periph);
    /* enable SMARTCARD */
    usart_smartcard_mode_enable(periph);

}

void i7816_hal_usart_rx_disable(i7816_hw_t* hw){
	i7816_usart_t* usart = hw->usart;
	usart_interrupt_disable(usart->dev, USART_INT_RBNE);
	usart_data_receive(usart->dev);
	if(usart->queue != NULL){
		xQueueReset(usart->queue);
	}
}

void i7816_hal_usart_init(i7816_hw_t* hw){
	i7816_usart_t* usart = hw->usart;

	if(usart->queue == NULL){
		usart->queue = xQueueCreate(256+6, sizeof(uint16_t));
	}
    /* enable peripheral clock  */
	rcu_periph_clock_enable(usart->rcu);
	// BSP_Uart_SetRxCallback(usart->id, i7816_usart_rx_cb);
    /* Enable USART clock */
	i7816_hal_usart_dev_init(usart->dev, hw->freq);
    /* USART interrupt configuration */
    nvic_irq_enable(usart->iqrn, 12, 0);
    /* enable USART0 receive interrupt */
    usart_interrupt_disable(usart->dev, USART_INT_RBNE);
	usart_enable(usart->dev);
}


static void i7816_hal_usart_config_byte_direction(uint32_t periph, bool inverse){

	if(inverse){
		usart_invert_config(periph, USART_DINV_ENABLE);
		usart_invert_config(periph, USART_TXPIN_ENABLE);
		usart_invert_config(periph, USART_RXPIN_ENABLE);
	}
	else{
		usart_invert_config(periph, USART_DINV_DISABLE);
		usart_invert_config(periph, USART_TXPIN_DISABLE);
		usart_invert_config(periph, USART_RXPIN_DISABLE);		
	}
}

static void usart_set_divider(uint32_t USARTx, uint32_t F, uint32_t D)
{
    uint32_t remainder;
    uint32_t integerdivider;
    uint32_t fractionaldivider;

    /* Integer part computing in case Oversampling mode is 16 Samples */
    integerdivider = F / D;
    //Fraction = remainder /D = DIV_Fraction / 16 => DIV_Fraction = remainder *16/D
    remainder = F % D;
//	    fractionaldivider = (remainder * (16 / 2)) / D;
	fractionaldivider = (remainder * 16) / D;	

    USART_BAUD(USARTx) = ((USART_BAUD_FRADIV | USART_BAUD_INTDIV) & (integerdivider << 4 | (fractionaldivider & 0x0F)));	
}


static void i7816_hal_usart_config_fidi(uint32_t periph, uint32_t freq, uint8_t FiDi){
    uint32_t F;
    uint32_t D;    
	uint32_t usart_freq = i7816_hal_usart_get_freq(periph);
    uint32_t frequency_fraction = usart_freq / freq;

    F = i7816_convert_fi_code_to_value(FiDi >> 4);
    D = i7816_convert_di_code_to_value(FiDi & 0x0F);
    F = F * frequency_fraction / 16;
    usart_set_divider(periph, F, D);
}

static void i7816_hal_usart_config_protocol(uint32_t periph, i7816_protocol_t protocol){
	switch (protocol)
	{
	case PROTOCOL_T0:{
		usart_stop_bit_set(periph, USART_STB_1_5BIT);
		usart_parity_config(periph, USART_PM_EVEN);
		usart_guard_time_config(periph, 1);
		usart_smartcard_mode_nack_enable(periph);
		usart_receiver_timeout_disable(periph);
		usart_block_length_config(periph, 0);
		usart_smartcard_autoretry_config(periph, 5);
	}
	break;

	case PROTOCOL_T1:{
		usart_stop_bit_set(periph, USART_STB_1BIT);
		usart_parity_config(periph, USART_PM_EVEN);
		usart_guard_time_config(periph, 0);
		usart_smartcard_mode_nack_disable(periph);
		usart_receiver_timeout_disable(periph);
		usart_block_length_config(periph, 0);
		usart_smartcard_autoretry_config(periph, 0);
	}
	break;
	case PROTOCOL_ANY:{
		usart_stop_bit_set(periph, USART_STB_1_5BIT);
		usart_parity_config(periph, USART_PM_NONE);
		usart_guard_time_config(periph, 1);
		usart_smartcard_mode_nack_disable(periph);
		usart_receiver_timeout_disable(periph);
		usart_block_length_config(periph, 0);
		usart_smartcard_autoretry_config(periph, 0);
	}
	break;
	default:
		I7816_LOG_ERR("unknown protocol: %d", protocol);
	}
}

static bool i7816_hal_usart_need_config(i7816_usart_t* usart, const i7816_hw_param_t* param){
	if(usart->protocol != param->protocol){
		return true;
	}
	if(usart->FiDi != param->FiDi){
		return true;
	}
	if(usart->inverse != param->inverse){
		return true;
	}
	return false;
}

void i7816_hal_usart_config(i7816_hw_t* hw, const i7816_hw_param_t* param){
	i7816_usart_t* usart = hw->usart;
	uint32_t dev = usart->dev;

	if(i7816_hal_usart_need_config(usart, param)){
/*
	GD32W515的usart修改参数时，需要disable usart，
	此时clock信号停止输出，enable后，clock信号恢复输出。
	SAM AV3芯片在clock信号恢复后，会发送ATR。
	因此我们采用pwm产生独立的clock，避免修改usart配置时，产生时钟停止的问题。
*/		
		usart_disable(dev);
		i7816_hal_usart_config_protocol(dev, param->protocol);
		i7816_hal_usart_config_byte_direction(dev, param->inverse);
		i7816_hal_usart_config_fidi(dev, hw->freq, param->FiDi);
		usart_enable(dev);
		usart->FiDi = param->FiDi;
		usart->protocol = param->protocol;
		usart->inverse = param->inverse;
	}
	usart_data_receive(dev);	
	xQueueReset(usart->queue);
	usart_interrupt_enable(dev, USART_INT_RBNE);
}

i7816_status_t i7816_hal_receive(i7816_hw_t* hw, uint16_t* rdata, uint32_t wait_clk){
	i7816_usart_t* usart = hw->usart;
	uint32_t dev = usart->dev;

	if(usart->queue == NULL){
		return I7816_S_NOT_READY;
	}

	if(SET == usart_flag_get(dev, USART_FLAG_FERR)){
		usart_data_receive(dev);
	}
	//按4.0MHz计算时间
	uint32_t wtime = wait_clk / 5000 + 3;	
	int ret = xQueueReceive(usart->queue, rdata, wtime / portTICK_PERIOD_MS);
	hw->param->last_time = i7816_hal_get_clk_count();
	if(ret != pdTRUE){
		return I7816_S_TIMEOUT;
	}

    return I7816_S_OK;
}

void i7816_hal_delay_guard_time(i7816_hw_t* hw, uint32_t gt_clk){
	uint32_t c;
	uint32_t last_time = hw->param->last_time;
	do{
		c = i7816_hal_get_clk_count();
	}while((uint32_t)(c - last_time) < gt_clk);
}

uint32_t i7816_guard_time_to_clk(i7816_guard_time_t gt, uint8_t FiDi){
	uint32_t clk = gt.extra_clk;
	return clk + i7816_etu2clk(gt.etu, FiDi);
}

i7816_status_t i7816_hal_send(i7816_hw_t* hw, uint8_t byte){
	i7816_usart_t* usart = hw->usart;
	if(usart->queue == NULL){
		return I7816_S_NOT_READY;
	}
	uint16_t tx_data = byte;
	if(xQueueSend(usart->queue, &tx_data, 0) != pdTRUE){
		return I7816_S_OVER_BUFFER_SIZE;
	}
    return I7816_S_OK;
}

i7816_status_t i7816_hal_send_byte(i7816_hw_t* hw, uint8_t byte){
	i7816_usart_t* usart = hw->usart;
	uint32_t dev = usart->dev;
    i7816_status_t err = I7816_S_OK;	
	uint32_t clk = 1000 * 10;

	i7816_hal_delay_guard_time(hw, i7816_guard_time_to_clk(hw->param->GT, hw->param->FiDi));
	uint32_t c1 = i7816_hal_get_clk_count();
	uint32_t c2;
	while(RESET == usart_flag_get(dev, USART_FLAG_TBE)){
		c2 = i7816_hal_get_clk_count();
		if((c2-c1) > clk) {
			break;
		}
	}
	if(RESET != usart_flag_get(dev, USART_FLAG_TC)){
		usart_flag_clear(dev, USART_FLAG_TC);
	}
	usart_data_transmit(dev, byte);

	c1 = i7816_hal_get_clk_count();
	while(RESET == usart_flag_get(dev, USART_FLAG_TC)){
		c2 = i7816_hal_get_clk_count();
		if((c2-c1) > clk) {
			err = I7816_S_TIMEOUT;
			LOG2_ERR("tx timout: %02X", byte);
			break;
		}
	}
	hw->param->last_time = i7816_hal_get_clk_count();
    return err;
}


void i7816_hal_setup(i7816_hw_t* hw, transfer_dir_t dir){
	i7816_usart_t* usart = hw->usart;
	uint32_t dev = usart->dev;
	
    if(dir == TRANSFER_IN){
		usart_flag_get(dev, USART_FLAG_FERR);
		usart_data_receive(dev);
		xQueueReset(usart->queue);
		usart_command_enable(dev, USART_CMD_RXFCMD);
		usart_interrupt_enable(dev, USART_INT_RBNE);
    }
	else{		
		usart_flag_get(dev, USART_FLAG_FERR);
		usart_data_receive(dev);
		usart_command_enable(dev, USART_CMD_RXFCMD);
		usart_interrupt_disable(dev, USART_INT_RBNE);
		xQueueReset(usart->queue);
		// xEventGroupClearBits(usart->tx_event, 1);
	}
	usart->transfer_direction = dir;
}

void i7816_hal_flush(i7816_hw_t* hw, transfer_dir_t dir){
	i7816_usart_t* usart = hw->usart;
	uint32_t dev = usart->dev;

	if(usart->queue == NULL){
		return;
	}

    if(dir == TRANSFER_IN){
		usart_data_receive(dev);
		xQueueReset(usart->queue);
    }
	else{
		uint16_t tx_data;
		//lock scheduler
		vTaskSuspendAll();
		while(xQueueReceive(usart->queue, &tx_data, 0)){
			i7816_hal_send_byte(hw, tx_data);
		}
		i7816_hal_setup(hw, TRANSFER_IN);
		xTaskResumeAll();
	}
}



